﻿using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Onetube.Entities.SearchrQuery;
using Onetube.Models.SearchVideo;
using Onetube.Providers.Interfaces;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Onetube.Providers
{
    public class YoutubeSearchProvider : IYoutubeSearchProvider
    {
        private YoutubeVideoProvider videoProvider;
        private YoutubeChannelProvider channelProvider;

        public async Task<SearchVideoResult> SearchTermAsync(string term, string regionCode, Entities.Enums.SearchOrder order, string maxResults, CancellationTokenSource cancelTask)
        {
            StringBuilder petitionUri = new StringBuilder("https://www.googleapis.com/youtube/v3/search?");

            petitionUri.AppendFormat("part={0}", "snippet");
            petitionUri.AppendFormat("&maxResults={0}", maxResults);
            petitionUri.AppendFormat("&order={0}", Helpers.SearchHelpers.ParseSearchOrderEnum(order));
            petitionUri.AppendFormat("&q={0}", term);
            petitionUri.AppendFormat("&regionCode={0}", regionCode);
            petitionUri.AppendFormat("&key={0}", AppKeys.API_KEY);
            var videoResult = new Models.SearchVideo.SearchVideoResult();
            
            var taskCompletitionSource = new TaskCompletionSource<SearchQueryResult>();
            
            var result = await ResolveRequest(petitionUri, taskCompletitionSource, cancelTask).ConfigureAwait(false);
            if (result != null)
            {
                videoResult.etag = result.etag;
                videoResult.kind = result.kind;
                videoResult.nextPageToken = result.nextPageToken;
                videoResult.pageInfo = new Models.SearchVideo.PageInfo { resultsPerPage = result.pageInfo.resultsPerPage, totalResults = result.pageInfo.totalResults };
                videoResult.prevPageToken = result.prevPageToken;
                videoResult.items = new List<Models.SearchVideo.Item>();
                if (result.items != null)
                {
                    if (result.items.Any())
                    {
                        videoProvider = new YoutubeVideoProvider();
                        channelProvider = new YoutubeChannelProvider();
                        string videoIds = string.Empty;
                        string channelIds = string.Empty;
                        int count = 0;
                        for (int i = 0; i <= result.items.Count - 1; i++)
                        {
                            count++;
                            var item = result.items.ElementAt(i);
                            if (item.id != null)
                            {
                                if (count >= result.items.Count)
                                {
                                    videoIds += item.id.videoId;
                                    channelIds += item.snippet.channelId;
                                }
                                else
                                {
                                    videoIds += item.id.videoId + ",";
                                    channelIds += item.snippet.channelId + ",";
                                }
                            }
                        }

                        var videoDataList = await videoProvider.GeVideoInfoAsync(videoIds, "MX", cancelTask).ConfigureAwait(false);
                        var channelDataList = await channelProvider.SearchChannelByIdAsync(channelIds, cancelTask).ConfigureAwait(false);
                        if (videoDataList != null)
                        {
                            foreach (var videoItem in result.items)
                            {
                                var dataItem = new Onetube.Models.SearchVideo.Item();
                              
                                dataItem.etag = videoResult.etag;
                                dataItem.id = new Onetube.Models.SearchVideo.Id { kind = videoItem.id.kind, videoId = videoItem.id.videoId };
                                dataItem.kind = videoItem.kind;
                                var snippet = new Onetube.Models.SearchVideo.Snippet();
                                snippet.channelId = videoItem.snippet.channelId;
                                snippet.channelTitle = videoItem.snippet.channelTitle;
                                snippet.description = videoItem.snippet.description;
                                snippet.liveBroadcastContent = videoItem.snippet.liveBroadcastContent;
                                snippet.publishedAt = videoItem.snippet.publishedAt;
                                snippet.title = videoItem.snippet.title;
                                snippet.thumbnails = new Onetube.Models.SearchVideo.Thumbnails 
                                {
                                    @default = new Onetube.Models.SearchVideo.Default { url = videoItem.snippet.thumbnails.@default.url },
                                    high = new Onetube.Models.SearchVideo.High { url = videoItem.snippet.thumbnails.high.url },
                                    medium = new Onetube.Models.SearchVideo.Medium { url = videoItem.snippet.thumbnails.medium.url }
                                };
                                var contentDetails = new Onetube.Models.SearchVideo.ContentDetails();
                                var correspondVideo = videoDataList.Items.FirstOrDefault(x => x.Id.Equals(videoItem.id.videoId));
                                if (correspondVideo != null)
                                {
                                    if (correspondVideo.ContentDetails != null)
                                    {
                                        contentDetails.caption = correspondVideo.ContentDetails.Caption;
                                        contentDetails.definition = correspondVideo.ContentDetails.Definition;
                                        contentDetails.dimension = correspondVideo.ContentDetails.Dimension;
                                        contentDetails.duration = correspondVideo.ContentDetails.Duration;
                                        contentDetails.licensedContent = correspondVideo.ContentDetails.LicensedContent;
                                    }
                                    snippet.contentDetails = contentDetails;

                                    var statistics = new Onetube.Models.SearchVideo.Statistics();
                                    if (correspondVideo.Statistics != null)
                                    {
                                        statistics.commentCount = correspondVideo.Statistics.CommentCount;
                                        statistics.dislikeCount = correspondVideo.Statistics.DislikeCount;
                                        statistics.favoriteCount = correspondVideo.Statistics.FavoriteCount;
                                        statistics.likeCount = correspondVideo.Statistics.LikeCount;
                                        statistics.viewCount = correspondVideo.Statistics.ViewCount;

                                        snippet.statistics = statistics;
                                    }
                                }
                              
                                dataItem.snippet = snippet;
                                if (channelDataList != null)
                                {
                                    if (channelDataList.Items != null)
                                        if (channelDataList.Items.Any())
                                        {
                                            var correspondChannel = channelDataList.Items.FirstOrDefault(x => x.Id.Equals(videoItem.snippet.channelId));
                                            if (correspondChannel != null)
                                            {
                                                dataItem.snippet.channelDetails = new ChannelSnippet();
                                                dataItem.snippet.channelDetails.Description = correspondChannel.Snippet.Description;
                                                dataItem.snippet.channelDetails.PublishedAt = correspondChannel.Snippet.PublishedAt;
                                                dataItem.snippet.channelDetails.Thumbnails = new Models.SearchVideo.Thumbnails
                                                {
                                                    @default = new Models.SearchVideo.Default
                                                    {
                                                        url = correspondChannel.Snippet.Thumbnails.Default.Url
                                                    },
                                                    high = new Models.SearchVideo.High
                                                    {
                                                        url = correspondChannel.Snippet.Thumbnails.High.Url
                                                    },
                                                    medium = new Models.SearchVideo.Medium
                                                    {
                                                        url = correspondChannel.Snippet.Thumbnails.Medium.Url
                                                    }
                                                };
                                                dataItem.snippet.channelDetails.Title = correspondChannel.Snippet.Title;
                                            }
                                        }
                                }
                                videoResult.items.Add(dataItem);
                            }
                            videoDataList = null;
                            channelDataList = null;
                            videoIds = null;
                            channelIds = null;
                        }
                    }
                }
                result = null;
            }

            return videoResult;
        }

        public Task<SearchQueryResult> SearchTermAsyncPrevPage(string prevPageToken, string term, string regionCode, Entities.Enums.SearchOrder order, string maxResults, CancellationTokenSource cancelTask)
        {
            StringBuilder petitionUri = new StringBuilder("https://www.googleapis.com/youtube/v3/search?");

            petitionUri.AppendFormat("part={0}", "snippet");
            petitionUri.AppendFormat("&maxResults={0}", maxResults);
            petitionUri.AppendFormat("&order={0}", Helpers.SearchHelpers.ParseSearchOrderEnum(order));
            petitionUri.AppendFormat("&q={0}", term);
            petitionUri.AppendFormat("&regionCode={0}", regionCode);
            petitionUri.AppendFormat("&pageToken={0}", prevPageToken);
            petitionUri.AppendFormat("&key={0}", AppKeys.API_KEY);

            var taskCompletitionSource = new TaskCompletionSource<SearchQueryResult>();

            return ResolveRequest(petitionUri, taskCompletitionSource, cancelTask);
        }

        public async Task<SearchVideoResult> SearchTermAsyncNextPage(string nextPageToken, string term, string regionCode, Entities.Enums.SearchOrder order, string maxResults, CancellationTokenSource cancelTask)
        {
            StringBuilder petitionUri = new StringBuilder("https://www.googleapis.com/youtube/v3/search?");

            petitionUri.AppendFormat("part={0}", "snippet");
            petitionUri.AppendFormat("&maxResults={0}", maxResults);
            petitionUri.AppendFormat("&order={0}", Helpers.SearchHelpers.ParseSearchOrderEnum(order));
            petitionUri.AppendFormat("&q={0}", term);
            petitionUri.AppendFormat("&regionCode={0}", regionCode);
            petitionUri.AppendFormat("&pageToken={0}", nextPageToken);
            petitionUri.AppendFormat("&key={0}", AppKeys.API_KEY);

            var taskCompletitionSource = new TaskCompletionSource<SearchQueryResult>();
            var videoResult = new Models.SearchVideo.SearchVideoResult();
            var result = await ResolveRequest(petitionUri, taskCompletitionSource, cancelTask).ConfigureAwait(false);
            if (result != null)
            {
                videoResult.etag = result.etag;
                videoResult.kind = result.kind;
                videoResult.nextPageToken = result.nextPageToken;
                videoResult.pageInfo = new Models.SearchVideo.PageInfo { resultsPerPage = result.pageInfo.resultsPerPage, totalResults = result.pageInfo.totalResults };
                videoResult.prevPageToken = result.prevPageToken;
                videoResult.items = new List<Models.SearchVideo.Item>();
                if (result.items != null)
                {
                    if (result.items.Any())
                    {
                        videoProvider = new YoutubeVideoProvider();
                        channelProvider = new YoutubeChannelProvider();
                        string videoIds = string.Empty;
                        string channelIds = string.Empty;
                        int count = 0;
                        for (int i = 0; i <= result.items.Count - 1; i++)
                        {
                            count++;
                            var item = result.items.ElementAt(i);
                            if (item.id != null)
                            {
                                if (count >= result.items.Count)
                                {
                                    videoIds += item.id.videoId;
                                    channelIds += item.snippet.channelId;
                                }
                                else
                                {
                                    videoIds += item.id.videoId + ",";
                                    channelIds += item.snippet.channelId + ",";
                                }
                            }
                        }

                        var videoDataList = await videoProvider.GeVideoInfoAsync(videoIds, "MX", cancelTask).ConfigureAwait(false);
                        var channelDataList = await channelProvider.SearchChannelByIdAsync(channelIds, cancelTask).ConfigureAwait(false);
                        if (videoDataList != null)
                        {
                            foreach (var videoItem in result.items)
                            {
                                var dataItem = new Onetube.Models.SearchVideo.Item();
                              
                                dataItem.etag = videoResult.etag;
                                dataItem.id = new Onetube.Models.SearchVideo.Id { kind = videoItem.id.kind, videoId = videoItem.id.videoId };
                                dataItem.kind = videoItem.kind;
                                var snippet = new Onetube.Models.SearchVideo.Snippet();
                                snippet.channelId = videoItem.snippet.channelId;
                                snippet.channelTitle = videoItem.snippet.channelTitle;
                                snippet.description = videoItem.snippet.description;
                                snippet.liveBroadcastContent = videoItem.snippet.liveBroadcastContent;
                                snippet.publishedAt = videoItem.snippet.publishedAt;
                                snippet.title = videoItem.snippet.title;
                                snippet.thumbnails = new Onetube.Models.SearchVideo.Thumbnails 
                                {
                                    @default = new Onetube.Models.SearchVideo.Default { url = videoItem.snippet.thumbnails.@default.url },
                                    high = new Onetube.Models.SearchVideo.High { url = videoItem.snippet.thumbnails.high.url },
                                    medium = new Onetube.Models.SearchVideo.Medium { url = videoItem.snippet.thumbnails.medium.url }
                                };
                                var contentDetails = new Onetube.Models.SearchVideo.ContentDetails();
                                var correspondVideo = videoDataList.Items.FirstOrDefault(x => x.Id.Equals(videoItem.id.videoId));
                                if (correspondVideo != null)
                                {
                                    if (correspondVideo.ContentDetails != null)
                                    {
                                        contentDetails.caption = correspondVideo.ContentDetails.Caption;
                                        contentDetails.definition = correspondVideo.ContentDetails.Definition;
                                        contentDetails.dimension = correspondVideo.ContentDetails.Dimension;
                                        contentDetails.duration = correspondVideo.ContentDetails.Duration;
                                        contentDetails.licensedContent = correspondVideo.ContentDetails.LicensedContent;
                                    }

                                    snippet.contentDetails = contentDetails;

                                    if (correspondVideo.Statistics != null)
                                    {
                                        var statistics = new Onetube.Models.SearchVideo.Statistics();
                                        statistics.commentCount = correspondVideo.Statistics.CommentCount;
                                        statistics.dislikeCount = correspondVideo.Statistics.DislikeCount;
                                        statistics.favoriteCount = correspondVideo.Statistics.FavoriteCount;
                                        statistics.likeCount = correspondVideo.Statistics.LikeCount;
                                        statistics.viewCount = correspondVideo.Statistics.ViewCount;
                                        snippet.statistics = statistics;
                                    }
                                }
                               
                                dataItem.snippet = snippet;
                                if (channelDataList != null)
                                {
                                    if (channelDataList.Items.Any())
                                    {
                                        var correspondChannel = channelDataList.Items.FirstOrDefault(x => x.Id.Equals(videoItem.snippet.channelId));
                                        if (correspondChannel != null)
                                        {
                                            dataItem.snippet.channelDetails = new ChannelSnippet();
                                            dataItem.snippet.channelDetails.Description = correspondChannel.Snippet.Description;
                                            dataItem.snippet.channelDetails.PublishedAt = correspondChannel.Snippet.PublishedAt;
                                            dataItem.snippet.channelDetails.Thumbnails = new Models.SearchVideo.Thumbnails
                                            {
                                                @default = new Models.SearchVideo.Default
                                                {
                                                    url = correspondChannel.Snippet.Thumbnails.Default.Url
                                                },
                                                high = new Models.SearchVideo.High
                                                {
                                                    url = correspondChannel.Snippet.Thumbnails.High.Url
                                                },
                                                medium = new Models.SearchVideo.Medium
                                                {
                                                    url = correspondChannel.Snippet.Thumbnails.Medium.Url
                                                }
                                            };
                                            dataItem.snippet.channelDetails.Title = correspondChannel.Snippet.Title;
                                        }
                                    }
                                }
                                videoResult.items.Add(dataItem);
                            }
                            videoDataList = null;
                            channelDataList = null;
                            videoIds = null;
                            channelIds = null;
                        }
                    }
                }
                result = null;
            }

            return videoResult;
        }

        public async Task<SearchVideoResult> SearchRecommendedAsync(string regionCode, Entities.Enums.SearchOrder order, string maxResults, CancellationTokenSource cancelTask)
        {
            StringBuilder petitionUri = new StringBuilder("https://www.googleapis.com/youtube/v3/search?");
           
            petitionUri.AppendFormat("part={0}", "snippet");
            petitionUri.AppendFormat("&maxResults={0}", maxResults);
            petitionUri.AppendFormat("&order={0}", Helpers.SearchHelpers.ParseSearchOrderEnum(order));
            petitionUri.AppendFormat("&regionCode={0}", regionCode);
            petitionUri.AppendFormat("&key={0}", AppKeys.API_KEY);
            var taskCompletitionSource = new TaskCompletionSource<SearchQueryResult>();
         
            var videoResult = new Models.SearchVideo.SearchVideoResult();
            var result = await ResolveRequest(petitionUri, taskCompletitionSource, cancelTask).ConfigureAwait(false);
             
            if (result != null)
            {
                videoResult.etag = result.etag;
                videoResult.kind = result.kind;
                videoResult.nextPageToken = result.nextPageToken;
                videoResult.pageInfo = new Models.SearchVideo.PageInfo { resultsPerPage = result.pageInfo.resultsPerPage, totalResults = result.pageInfo.totalResults };
                videoResult.prevPageToken = result.prevPageToken;
                videoResult.items = new List<Models.SearchVideo.Item>();
                if (result.items != null)
                {
                    if (result.items.Any())
                    {
                        videoProvider = new YoutubeVideoProvider();
                        channelProvider = new YoutubeChannelProvider();
                        string videoIds = string.Empty;
                        string channelIds = string.Empty;
                        int count = 0;
                        for (int i = 0; i <= result.items.Count - 1; i++)
                        {
                            count++;
                            var item = result.items.ElementAt(i);
                            if (item.id != null)
                            {
                                if (count >= result.items.Count)
                                {
                                    videoIds += item.id.videoId;
                                    channelIds += item.snippet.channelId;
                                }
                                else
                                {
                                    videoIds += item.id.videoId + ",";
                                    channelIds += item.snippet.channelId + ",";
                                }
                            }
                        }

                        var videoDataList = await videoProvider.GeVideoInfoAsync(videoIds, "MX", cancelTask).ConfigureAwait(false);
                        var channelDataList = await channelProvider.SearchChannelByIdAsync(channelIds, cancelTask).ConfigureAwait(false);
                        if (videoDataList != null)
                        {
                            foreach (var videoItem in result.items)
                            {
                                var dataItem = new Onetube.Models.SearchVideo.Item();
                              
                                dataItem.etag = videoResult.etag;
                                dataItem.id = new Onetube.Models.SearchVideo.Id { kind = videoItem.id.kind, videoId = videoItem.id.videoId };
                                dataItem.kind = videoItem.kind;
                                var snippet = new Onetube.Models.SearchVideo.Snippet();
                                snippet.channelId = videoItem.snippet.channelId;
                                snippet.channelTitle = videoItem.snippet.channelTitle;
                                snippet.description = videoItem.snippet.description;
                                snippet.liveBroadcastContent = videoItem.snippet.liveBroadcastContent;
                                snippet.publishedAt = videoItem.snippet.publishedAt;
                                snippet.title = videoItem.snippet.title;
                                snippet.thumbnails = new Onetube.Models.SearchVideo.Thumbnails 
                                {
                                    @default = new Onetube.Models.SearchVideo.Default { url = videoItem.snippet.thumbnails.@default.url },
                                    high = new Onetube.Models.SearchVideo.High { url = videoItem.snippet.thumbnails.high.url },
                                    medium = new Onetube.Models.SearchVideo.Medium { url = videoItem.snippet.thumbnails.medium.url }
                                };
                                var contentDetails = new Onetube.Models.SearchVideo.ContentDetails();
                                var correspondVideo = videoDataList.Items.FirstOrDefault(x => x.Id.Equals(videoItem.id.videoId));
                                if (correspondVideo != null)
                                {
                                    contentDetails.caption = correspondVideo.ContentDetails.Caption;
                                    contentDetails.definition = correspondVideo.ContentDetails.Definition;
                                    contentDetails.dimension = correspondVideo.ContentDetails.Dimension;
                                    contentDetails.duration = correspondVideo.ContentDetails.Duration;
                                    contentDetails.licensedContent = correspondVideo.ContentDetails.LicensedContent;
                                }

                                snippet.contentDetails = contentDetails;

                                var statistics = new Onetube.Models.SearchVideo.Statistics();
                                statistics.commentCount = correspondVideo.Statistics.CommentCount;
                                statistics.dislikeCount = correspondVideo.Statistics.DislikeCount;
                                statistics.favoriteCount = correspondVideo.Statistics.FavoriteCount;
                                statistics.likeCount = correspondVideo.Statistics.LikeCount;
                                statistics.viewCount = correspondVideo.Statistics.ViewCount;

                                snippet.statistics = statistics;
                                dataItem.snippet = snippet;
                                if (channelDataList != null)
                                {
                                    
                                    if (channelDataList.Items!=null && channelDataList.Items.Any())
                                    {
                                        var correspondChannel = channelDataList.Items.FirstOrDefault(x => x.Id.Equals(videoItem.snippet.channelId));
                                        if (correspondChannel != null)
                                        {
                                            dataItem.snippet.channelDetails = new ChannelSnippet();
                                            dataItem.snippet.channelDetails.Description = correspondChannel.Snippet.Description;
                                            dataItem.snippet.channelDetails.PublishedAt = correspondChannel.Snippet.PublishedAt;
                                            dataItem.snippet.channelDetails.Thumbnails = new Models.SearchVideo.Thumbnails
                                            {
                                                @default = new Models.SearchVideo.Default
                                                {
                                                    url = correspondChannel.Snippet.Thumbnails.Default.Url
                                                },
                                                high = new Models.SearchVideo.High
                                                {
                                                    url = correspondChannel.Snippet.Thumbnails.High.Url
                                                },
                                                medium = new Models.SearchVideo.Medium
                                                {
                                                    url = correspondChannel.Snippet.Thumbnails.Medium.Url
                                                }
                                            };
                                            dataItem.snippet.channelDetails.Title = correspondChannel.Snippet.Title;
                                        }
                                    }
                                }
                                videoResult.items.Add(dataItem);
                            }
                            videoDataList = null;
                            channelDataList = null;
                            videoIds = null;
                            channelIds = null;
                        }
                    }
                }
                result = null;
            }

            return videoResult;
            // return ResolveRequest(petitionUri, taskCompletitionSource).Result;
        }

        public Task<SearchQueryResult> SearchRecommendedPrevPageAsync(string prevPageToken, string regionCode, Entities.Enums.SearchOrder order, string maxResults, CancellationTokenSource cancelTask)
        {
            StringBuilder petitionUri = new StringBuilder("https://www.googleapis.com/youtube/v3/search?");

            petitionUri.AppendFormat("part={0}", "snippet");
            petitionUri.AppendFormat("&maxResults={0}", maxResults);
            petitionUri.AppendFormat("&order={0}", Helpers.SearchHelpers.ParseSearchOrderEnum(order));
            petitionUri.AppendFormat("&regionCode={0}", regionCode);
            petitionUri.AppendFormat("&pageToken={0}", prevPageToken);
            petitionUri.AppendFormat("&key={0}", AppKeys.API_KEY);

            var taskCompletitionSource = new TaskCompletionSource<SearchQueryResult>();

            return ResolveRequest(petitionUri, taskCompletitionSource, cancelTask);
        }

        public async Task<SearchVideoResult> SearchRecommendedNextPageAsync(string nextPageToken, string regionCode, Entities.Enums.SearchOrder order, string maxResults, CancellationTokenSource cancelTask)
        {
            StringBuilder petitionUri = new StringBuilder("https://www.googleapis.com/youtube/v3/search?");

            petitionUri.AppendFormat("part={0}", "snippet");
            petitionUri.AppendFormat("&maxResults={0}", maxResults);
            petitionUri.AppendFormat("&order={0}", Helpers.SearchHelpers.ParseSearchOrderEnum(order));
            petitionUri.AppendFormat("&pageToken={0}", nextPageToken);
            petitionUri.AppendFormat("&regionCode={0}", regionCode);
            petitionUri.AppendFormat("&key={0}", AppKeys.API_KEY);
            var taskCompletitionSource = new TaskCompletionSource<SearchQueryResult>();
            var videoResult = new Models.SearchVideo.SearchVideoResult();
            var result = await ResolveRequest(petitionUri, taskCompletitionSource, cancelTask).ConfigureAwait(false);

            if (result != null)
            {
                videoResult.etag = result.etag;
                videoResult.kind = result.kind;
                videoResult.nextPageToken = result.nextPageToken;
                videoResult.pageInfo = new Models.SearchVideo.PageInfo { resultsPerPage = result.pageInfo.resultsPerPage, totalResults = result.pageInfo.totalResults };
                videoResult.prevPageToken = result.prevPageToken;
                videoResult.items = new List<Models.SearchVideo.Item>();
                if (result.items != null)
                {
                    if (result.items.Any())
                    {
                        videoProvider = new YoutubeVideoProvider();
                        channelProvider = new YoutubeChannelProvider();
                        string videoIds = string.Empty;
                        string channelIds = string.Empty;
                        int count = 0;
                        for (int i = 0; i <= result.items.Count - 1; i++)
                        {
                            count++;
                            var item = result.items.ElementAt(i);
                            if (item.id != null)
                            {
                                if (count >= result.items.Count)
                                {
                                    videoIds += item.id.videoId;
                                    channelIds += item.snippet.channelId;
                                }
                                else
                                {
                                    videoIds += item.id.videoId + ",";
                                    channelIds += item.snippet.channelId + ",";
                                }
                            }
                        }

                        var videoDataList = await videoProvider.GeVideoInfoAsync(videoIds, "MX", cancelTask).ConfigureAwait(false);
                        var channelDataList = await channelProvider.SearchChannelByIdAsync(channelIds, cancelTask).ConfigureAwait(false);
                        if (videoDataList != null)
                        {
                            foreach (var videoItem in result.items)
                            {
                                var dataItem = new Onetube.Models.SearchVideo.Item();

                                dataItem.etag = videoResult.etag;
                                dataItem.id = new Onetube.Models.SearchVideo.Id { kind = videoItem.id.kind, videoId = videoItem.id.videoId };
                                dataItem.kind = videoItem.kind;
                                var snippet = new Onetube.Models.SearchVideo.Snippet();
                                snippet.channelId = videoItem.snippet.channelId;
                                snippet.channelTitle = videoItem.snippet.channelTitle;
                                snippet.description = videoItem.snippet.description;
                                snippet.liveBroadcastContent = videoItem.snippet.liveBroadcastContent;
                                snippet.publishedAt = videoItem.snippet.publishedAt;
                                snippet.title = videoItem.snippet.title;
                                snippet.thumbnails = new Onetube.Models.SearchVideo.Thumbnails
                                {
                                    @default = new Onetube.Models.SearchVideo.Default { url = videoItem.snippet.thumbnails.@default.url },
                                    high = new Onetube.Models.SearchVideo.High { url = videoItem.snippet.thumbnails.high.url },
                                    medium = new Onetube.Models.SearchVideo.Medium { url = videoItem.snippet.thumbnails.medium.url }
                                };
                                var contentDetails = new Onetube.Models.SearchVideo.ContentDetails();
                                var correspondVideo = videoDataList.Items.FirstOrDefault(x => x.Id.Equals(videoItem.id.videoId));
                                if (correspondVideo != null)
                                {
                                    contentDetails.caption = correspondVideo.ContentDetails.Caption;
                                    contentDetails.definition = correspondVideo.ContentDetails.Definition;
                                    contentDetails.dimension = correspondVideo.ContentDetails.Dimension;
                                    contentDetails.duration = correspondVideo.ContentDetails.Duration;
                                    contentDetails.licensedContent = correspondVideo.ContentDetails.LicensedContent;
                                }

                                snippet.contentDetails = contentDetails;

                                var statistics = new Onetube.Models.SearchVideo.Statistics();
                                statistics.commentCount = correspondVideo.Statistics.CommentCount;
                                statistics.dislikeCount = correspondVideo.Statistics.DislikeCount;
                                statistics.favoriteCount = correspondVideo.Statistics.FavoriteCount;
                                statistics.likeCount = correspondVideo.Statistics.LikeCount;
                                statistics.viewCount = correspondVideo.Statistics.ViewCount;

                                snippet.statistics = statistics;
                                dataItem.snippet = snippet;
                                if (channelDataList != null)
                                {
                                    if (channelDataList.Items.Any())
                                    {
                                        var correspondChannel = channelDataList.Items.FirstOrDefault(x => x.Id.Equals(videoItem.snippet.channelId));
                                        if (correspondChannel != null)
                                        {
                                            dataItem.snippet.channelDetails = new ChannelSnippet();
                                            dataItem.snippet.channelDetails.Description = correspondChannel.Snippet.Description;
                                            dataItem.snippet.channelDetails.PublishedAt = correspondChannel.Snippet.PublishedAt;
                                            dataItem.snippet.channelDetails.Thumbnails = new Models.SearchVideo.Thumbnails
                                            {
                                                @default = new Models.SearchVideo.Default
                                                {
                                                    url = correspondChannel.Snippet.Thumbnails.Default.Url
                                                },
                                                high = new Models.SearchVideo.High
                                                {
                                                    url = correspondChannel.Snippet.Thumbnails.High.Url
                                                },
                                                medium = new Models.SearchVideo.Medium
                                                {
                                                    url = correspondChannel.Snippet.Thumbnails.Medium.Url
                                                }
                                            };
                                            dataItem.snippet.channelDetails.Title = correspondChannel.Snippet.Title;
                                        }
                                    }
                                }
                                videoResult.items.Add(dataItem);
                            }
                            videoDataList = null;
                            channelDataList = null;
                            videoIds = null;
                            channelIds = null;
                        }
                    }
                }
                result = null;
            }

            return videoResult;
        }

        public async Task<Entities.ChannelsQuery.ChannelsQueryResult> SearchChannelByTermAsync(string term, string regionCode, Entities.Enums.SearchOrder order, string maxResults, CancellationTokenSource cancelTask)
        {
            StringBuilder petitionUri = new StringBuilder("https://www.googleapis.com/youtube/v3/search?");

            petitionUri.AppendFormat("part={0}", "snippet");
            petitionUri.AppendFormat("&maxResults={0}", maxResults);
            petitionUri.AppendFormat("&order={0}", Helpers.SearchHelpers.ParseSearchOrderEnum(order));
            petitionUri.AppendFormat("&q={0}", term);
            petitionUri.AppendFormat("&type={0}", "channel");
            petitionUri.AppendFormat("&regionCode={0}", regionCode);
            petitionUri.AppendFormat("&key={0}", AppKeys.API_KEY);
            var taskCompletitionSource = new TaskCompletionSource<Entities.ChannelSearchQuery.ChannelSearchQueryResult>();
         
            var result = await ResolveRequest(petitionUri, taskCompletitionSource, cancelTask).ConfigureAwait(false);
            if (result != null)
            {
                if (result.Items != null)
                {
                    string channelIds = string.Empty;
                    int count = 0;
                    for (int i = 0; i <= result.Items.Count() - 1; i++)
                    {
                        count++;
                        var item = result.Items.ElementAt(i);
                        if (item.Id != null)
                        {
                            if (count >= result.Items.Count())
                            {
                                channelIds += item.Id.ChannelId;
                            }
                            else
                            {
                                channelIds += item.Id.ChannelId + ",";
                            }
                        }
                    }

                    var channelProvider = new Providers.YoutubeChannelProvider();
                    var channelList = await channelProvider.SearchChannelByIdAsync(channelIds, cancelTask).ConfigureAwait(false);
                    channelList.NextPageToken = result.NextPageToken;
                    channelProvider = null;
                    result = null;
                    channelIds = string.Empty;
                    return channelList;
                }
            }
            result = null;
            return null;
        }

        public Task<Entities.ChannelsQuery.ChannelsQueryResult> SearchChannelByTermAsyncPrevPage(string prevPageToken, string term, string regionCode, Entities.Enums.SearchOrder order, string maxResults, CancellationTokenSource cancelTask)
        {
            throw new NotImplementedException();
        }

        public async Task<Entities.ChannelsQuery.ChannelsQueryResult> SearchChannelByTermAsyncNextPage(string nextPageToken, string term, string regionCode, Entities.Enums.SearchOrder order, string maxResults, CancellationTokenSource cancelTask)
        {
            StringBuilder petitionUri = new StringBuilder("https://www.googleapis.com/youtube/v3/search?");

            petitionUri.AppendFormat("part={0}", "snippet");
            petitionUri.AppendFormat("&maxResults={0}", maxResults);
            petitionUri.AppendFormat("&order={0}", Helpers.SearchHelpers.ParseSearchOrderEnum(order));
            petitionUri.AppendFormat("&type={0}", "channel");
            petitionUri.AppendFormat("&q={0}", term);
            petitionUri.AppendFormat("&pageToken={0}", nextPageToken);
            petitionUri.AppendFormat("&regionCode={0}", regionCode);
            petitionUri.AppendFormat("&key={0}", AppKeys.API_KEY);
            var taskCompletitionSource = new TaskCompletionSource<Entities.ChannelSearchQuery.ChannelSearchQueryResult>();
          
            var result = await ResolveRequest(petitionUri, taskCompletitionSource, cancelTask);
            if (result != null)
            {
                if (result.Items != null)
                {
                    string channelIds = string.Empty;
                    int count = 0;
                    for (int i = 0; i <= result.Items.Count() - 1; i++)
                    {
                        count++;
                        var item = result.Items.ElementAt(i);
                        if (item.Id != null)
                        {
                            if (count >= result.Items.Count())
                            {
                                channelIds += item.Id.ChannelId;
                            }
                            else
                            {
                                channelIds += item.Id.ChannelId + ",";
                            }
                        }
                    }

                    var channelProvider = new Providers.YoutubeChannelProvider();
                    var channelList = await channelProvider.SearchChannelByIdAsync(channelIds, cancelTask).ConfigureAwait(false);
                    channelList.NextPageToken = result.NextPageToken;
                    channelProvider = null;
                    result = null;
                    channelIds = string.Empty;
                    return channelList;
                }
            }
            result = null;
            return null;
            
        }

        private async Task<SearchQueryResult> ResolveRequest(StringBuilder petitionUri, TaskCompletionSource<SearchQueryResult> taskCompletitionSource, CancellationTokenSource cancelTask)
        {
            if (cancelTask == null)
            {
                cancelTask = new CancellationTokenSource();
            }
        
            using (HttpClient client = new HttpClient())
            {
                HttpResponseMessage response = await client.GetAsync(petitionUri.ToString(), cancelTask.Token).ConfigureAwait(false);
                
                string resultJson;
                using (StreamReader reader = new StreamReader(await response.Content.ReadAsStreamAsync().ConfigureAwait(false), Encoding.UTF8))
                {
                    try
                    {
                        resultJson = await reader.ReadToEndAsync().ConfigureAwait(false);

                        if (!string.IsNullOrEmpty(resultJson))
                        {
                            var entries = JsonConvert.DeserializeObject<SearchQueryResult>(resultJson);

                            taskCompletitionSource.SetResult(entries);
                            resultJson = null;
                            entries = null;
                        }
                        else
                        {
                            taskCompletitionSource.SetResult(null);
                        }
                        response.Dispose();
                    }
                    catch (Exception ex)
                    {
                        taskCompletitionSource.SetException(ex);
                    }
                }
            }
            return await taskCompletitionSource.Task;
        }

        private async Task<Entities.PlayListSearchQueryResult.PlayListSearchQueryResult> ResolveRequest(StringBuilder petitionUri, TaskCompletionSource<Entities.PlayListSearchQueryResult.PlayListSearchQueryResult> taskCompletitionSource, CancellationTokenSource cancelTask)
        {
            if (cancelTask == null)
            {
                cancelTask = new CancellationTokenSource();
            }
          
            using (HttpClient client = new HttpClient())
            {
                HttpResponseMessage response = await client.GetAsync(petitionUri.ToString(), cancelTask.Token).ConfigureAwait(false);
                
                string resultJson;
                using (StreamReader reader = new StreamReader(await response.Content.ReadAsStreamAsync().ConfigureAwait(false), Encoding.UTF8))
                {
                    try
                    {
                        resultJson = await reader.ReadToEndAsync().ConfigureAwait(false);

                        if (!string.IsNullOrEmpty(resultJson))
                        {
                            var entries = JsonConvert.DeserializeObject<Entities.PlayListSearchQueryResult.PlayListSearchQueryResult>(resultJson);

                            taskCompletitionSource.SetResult(entries);
                            resultJson = null;
                            entries = null;
                        }
                        else
                        {
                            taskCompletitionSource.SetResult(null);
                        }
                        response.Dispose();
                    }
                    catch (Exception ex)
                    {
                        taskCompletitionSource.SetException(ex);
                    }
                }
            }
            return await taskCompletitionSource.Task;
        }

        private async Task<Entities.ChannelSearchQuery.ChannelSearchQueryResult> ResolveRequest(StringBuilder petitionUri, TaskCompletionSource<Entities.ChannelSearchQuery.ChannelSearchQueryResult> taskCompletitionSource, CancellationTokenSource cancelTask)
        {
            if (cancelTask == null)
            {
                cancelTask = new CancellationTokenSource();
            }
       
           
            using (HttpClient client = new HttpClient())
            {
                HttpResponseMessage response = await client.GetAsync(petitionUri.ToString(), cancelTask.Token).ConfigureAwait(false);
                
                string resultJson;
                using (StreamReader reader = new StreamReader(await response.Content.ReadAsStreamAsync().ConfigureAwait(false), Encoding.UTF8))
                {
                    try
                    {
                        resultJson = await reader.ReadToEndAsync().ConfigureAwait(false);

                        if (!string.IsNullOrEmpty(resultJson))
                        {
                            var entries = JsonConvert.DeserializeObject<Entities.ChannelSearchQuery.ChannelSearchQueryResult>(resultJson);

                            taskCompletitionSource.SetResult(entries);
                            resultJson = null;
                            entries = null;
                        }
                        else
                        {
                            taskCompletitionSource.SetResult(null);
                        }
                        response.Dispose();
                    }
                    catch (Exception ex)
                    {
                        taskCompletitionSource.SetException(ex);
                    }
                }
            }
            return await taskCompletitionSource.Task;
        }

        /// <summary>
        /// string.Format("https://clients1.google.com/complete/search?client=youtube&hl={0}&gl={1}&q={2}&callback=google.sbox.p0&alt=json", MainViewModel.Instance.AppSettings.CurrentLanguageCulture.TwoLetterISOLanguageName, MainViewModel.Instance.AppSettings.CurrentRegion, this.SearchText);
        /// </summary>
        /// <returns></returns>

        public async Task<List<string>> GetSuggestedResultsAsync(string languageCode, string regionCode, string textToSearch, CancellationTokenSource cancelTask)
        {
            List<string> suggestions = new List<string>();
            string result = string.Empty;
            using (HttpClient client = new HttpClient())
            {
                StringBuilder petitionUri = new StringBuilder("https://clients1.google.com/complete/search?client=youtube");
                petitionUri.AppendFormat("&hl={0}", languageCode);
                //petitionUri.AppendFormat("&gl={0}", regionCode);
                petitionUri.AppendFormat("&q={0}", textToSearch);
                petitionUri.Append("&callback=google.sbox.p0&alt=json");
                HttpResponseMessage response = await client.GetAsync(petitionUri.ToString()).ConfigureAwait(false);
            
                result = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
                response.Dispose();
            }

            if (!string.IsNullOrEmpty(result))
            {
                JObject jObjects;
                try
                {
                    result = result.Substring(0, result.Length).Replace("google.sbox.p0 && google.sbox.p0(", "{result:").Replace(")", "}");
                    jObjects = JObject.Parse(result);
                }
                catch (Exception exception)
                {
                    return null;
                }

                foreach (JToken item in (IEnumerable<JToken>)jObjects["result"][1])
                {
                    if (suggestions.Contains(item[0].JsonValueToString()))
                    {
                        continue;
                    }
                    suggestions.Add(item[0].JsonValueToString());
                }
                  result = null;
                  jObjects = null;
                return suggestions;
            }
          
          
            return null;
        }

        public async Task<Models.SearchPlayListResult> SearchPlayListByTermAsync(string term, string regionCode, Entities.Enums.SearchOrder order, string maxResults, CancellationTokenSource cancelTask)
        {
            StringBuilder petitionUri = new StringBuilder("https://www.googleapis.com/youtube/v3/search?");

            petitionUri.AppendFormat("part={0}", "snippet");
            petitionUri.AppendFormat("&maxResults={0}", maxResults);
            petitionUri.AppendFormat("&order={0}", Helpers.SearchHelpers.ParseSearchOrderEnum(order));
            petitionUri.AppendFormat("&type={0}", "playlist");
            petitionUri.AppendFormat("&q={0}", term);
            // petitionUri.AppendFormat("&pageToken={0}", nextPageToken);
            petitionUri.AppendFormat("&regionCode={0}", regionCode);
            petitionUri.AppendFormat("&key={0}", AppKeys.API_KEY);
            var taskCompletitionSource = new TaskCompletionSource<Entities.PlayListSearchQueryResult.PlayListSearchQueryResult>();
            var result = await ResolveRequest(petitionUri, taskCompletitionSource, cancelTask).ConfigureAwait(false);
            var list = new Models.SearchPlayListResult();
            list.Items = new List<Entities.PlayListQueryResult.Item>();
            if (result != null)
            {
                var playListItemProvider = new Providers.YoutubePlayListItemProvider();
                list.NextPageToken = result.NextPageToken;
                
                if (result.Items.Any())
                {
                    foreach (var item in result.Items)
                    {
                        var info = await playListItemProvider.GetPlayListInfoAsync(item.Id.PlaylistId, "1", cancelTask).ConfigureAwait(false);
                        var listItem = new Entities.PlayListQueryResult.Item();
                        listItem.Id = item.Id.PlaylistId;
                        listItem.Kind = item.Kind;
                        var snippet = new Entities.PlayListQueryResult.Snippet();
                        snippet.ChannelId = item.Snippet.ChannelId;
                        snippet.ChannelTitle = item.Snippet.ChannelTitle;
                        snippet.Title = item.Snippet.Title;
                        snippet.Thumbnails = new Entities.PlayListQueryResult.Thumbnails
                        {
                            Default = new Entities.PlayListQueryResult.Default { Url = item.Snippet.Thumbnails.Default.Url },
                            Medium = new Entities.PlayListQueryResult.Medium { Url = item.Snippet.Thumbnails.Medium.Url },
                            High = new Entities.PlayListQueryResult.High { Url = item.Snippet.Thumbnails.High.Url }
                        };
                        listItem.Snippet = snippet;
                        listItem.VideosCount = info.PageInfo.TotalResults;
                        info = null;
                        list.Items.Add(listItem);
                    }
                }
            }
            result = null;
            return list;
        }

        public Task<Models.SearchPlayListResult> SearchPlayListByTermAsyncPrevPage(string prevPageToken, string term, string regionCode, Entities.Enums.SearchOrder order, string maxResults, CancellationTokenSource cancelTask)
        {
            throw new NotImplementedException();
        }

        public async Task<Models.SearchPlayListResult> SearchPlayListByTermAsyncNextPage(string nextPageToken, string term, string regionCode, Entities.Enums.SearchOrder order, string maxResults, CancellationTokenSource cancelTask)
        {
            StringBuilder petitionUri = new StringBuilder("https://www.googleapis.com/youtube/v3/search?");

            petitionUri.AppendFormat("part={0}", "snippet");
            petitionUri.AppendFormat("&maxResults={0}", maxResults);
            petitionUri.AppendFormat("&order={0}", Helpers.SearchHelpers.ParseSearchOrderEnum(order));
            petitionUri.AppendFormat("&type={0}", "playlist");
            petitionUri.AppendFormat("&q={0}", term);
            petitionUri.AppendFormat("&pageToken={0}", nextPageToken);
            petitionUri.AppendFormat("&regionCode={0}", regionCode);
            petitionUri.AppendFormat("&key={0}", AppKeys.API_KEY);
            var taskCompletitionSource = new TaskCompletionSource<Entities.PlayListSearchQueryResult.PlayListSearchQueryResult>();
            var result = await ResolveRequest(petitionUri, taskCompletitionSource, cancelTask).ConfigureAwait(false);
            var list = new Models.SearchPlayListResult();
            list.Items = new List<Entities.PlayListQueryResult.Item>();
            if (result != null)
            {
                var playListItemProvider = new Providers.YoutubePlayListItemProvider();
                list.NextPageToken = result.NextPageToken;
                
                if (result.Items.Any())
                {
                    foreach (var item in result.Items)
                    {
                        var info = await playListItemProvider.GetPlayListInfoAsync(item.Id.PlaylistId, "1", cancelTask).ConfigureAwait(false);
                        var listItem = new Entities.PlayListQueryResult.Item();
                        listItem.Id = item.Id.PlaylistId;
                        listItem.Kind = item.Kind;
                        var snippet = new Entities.PlayListQueryResult.Snippet();
                        snippet.ChannelId = item.Snippet.ChannelId;
                        snippet.ChannelTitle = item.Snippet.ChannelTitle;
                        snippet.Title = item.Snippet.Title;
                        snippet.Thumbnails = new Entities.PlayListQueryResult.Thumbnails
                        {
                            Default = new Entities.PlayListQueryResult.Default { Url = item.Snippet.Thumbnails.Default.Url },
                            Medium = new Entities.PlayListQueryResult.Medium { Url = item.Snippet.Thumbnails.Medium.Url },
                            High = new Entities.PlayListQueryResult.High { Url = item.Snippet.Thumbnails.High.Url }
                        };
                        listItem.Snippet = snippet;
                        listItem.VideosCount = info.PageInfo.TotalResults;
                        info = null;
                        list.Items.Add(listItem);
                    }
                }
            }
            result = null;
            return list;
        }
    }
}